#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <iostream>

#include "../ConnectMsg.h"
#include "ServerProcess.h"

using std::cout;
using std::endl;

const int MAXFDS = 5000;

void err_says(const char* msg)
{
	cout << msg << endl;
	cout << errno << endl;
}

void err_quit(const char* msg)
{
	err_says(msg);
	exit(EXIT_FAILURE);
}

int setNoBlocking(int sockfd)
{
	int opts = fcntl(sockfd, F_GETFL);
	if (opts < 0)
	{
		return -1;
	}
	opts = opts | O_NONBLOCK;
	if (fcntl(sockfd, F_SETFL, opt) < 0)
	{
		return -1;
	}
	return 0;
}

int createSocket()
{
	int sockfd, n;
	sockaddr_in servaddr;

	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_says("socket error");

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(19877);
	if (inet_pton(AF_INET, "127.0.0.1",&servaddr.sin_addr) <= 0)
		err_says("inet_pton rror for ip address");

	if (connect(sockfd, (sockaddr *) &servaddr, sizeof(servaddr)) < 0)
		err_says("connect error");

	return sockfd;
}

int main(int argc, char** argv)
{
	int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
	ssize_t n;
	pid_t childpid;
	socklen_t clilen;
	sockaddr_in cliaddr, servaddr;

	epoll_event ev, events[20];
	if ((epfd = epoll_create(256)) == -1)
	{
		err_quit("epoll create failed.");
	}

	if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
		err_quit("socket failed");

	if (setNoBlocking(listenfd) < 0)
	{
		err_quit("fcntl failed");
	}

	ev.data.fd = listenfd;
	ev.events = EPOLLIN|EPOLLET;
	epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(19877);

	if ( bind(listenfd, (sockaddr *) &servaddr, sizeof(servaddr)) == -1) 
	{
		cout << errno << endl;
		err_quit("bind faieled");
	}

	if (listen(listenfd, 1024) != 0)
	{
		err_quit("listen failed");
	}

	maxi = 0;
	const int BUF_LEN = 1024;
	unsigned char buffer[BUF_LEN];
	ServerProcess servProc("test");
	for (;;)
	{
		//TODO 超时，最大任务数
		nfds = epoll_wait(epfd, events, 20, 500);

		for (i=0; i<nfds; ++i)
		{
			if (events[i].data.fd==listenfd)
			{
				clilen = sizeof(cliaddr);
				if ((connfd = accept(listenfd, (sockaddr *)&cliaddr, &clilen)) == -1)
				{
					err_says("accept failed");
				}

				int opts = fcntl(listenfd, F_GETFL);
				opts = opts | O_NONBLOCK;
				fcntl(listenfd, F_SETFL, opts);

				ev.data.fd = connfd;
				ev.events = EPOLLIN | EPOLLET;
				epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
			}
			else if (events[i].events&EPOLLIN)
			{
				if ((sockfd = events[i].data.fd) < 0)
					continue;
				ssize_t reciveSize;
				int processSize = 0;
				while ( (reciveSize = read(sockfd, buffer, BUF_LEN)) > 0 ||
						(reciveSize < 0 && errno == EINTR) )
				{
				    processSize = servProc.Recive(sockfd, buffer, reciveSize);
					if (processSize == -1)
					{
						continue;
					}

					unsigned char* processBuffer =
					   	new unsigned char[processSize];

					if (-1 == servProc.GetPack(sockfd, processBuffer,
								processSize))
					{
						err_says("GetPack error");
					}

					buffer[0] = servProc.Process(processBuffer, processSize);

					// 写回答复给client
					if (write(sockfd, buffer,1) < 0)
					{
						err_says("write error");
					}
					close(sockfd);
					events[i].data.fd = -1;
					break;
				}

				if (reciveSize <= 0)
				{
					close(sockfd);
					events[i].data.fd = -1;
					err_says("read error");
				}
			}
		}
	}
}
